﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Emit;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Aribaccio.Device;
using Aribaccio.Logger;
using BDPAutodetect.Models;

namespace BDPAutodetect.Hardware
{
    /// <summary>
    /// 条码钩
    /// </summary>
    public class BarcodeHookEx
    {      
        /// <summary>
        /// 条码反馈事件
        /// </summary>
        public event Action<BarcodeMessage>? BarcodeHookEvent;
        /// <summary>
        /// 声明键盘钩子处理的初始值
        /// </summary>
        protected int keyboardHookID;
        /// <summary>
        /// 定义成静态，这样不会抛出回收异常
        /// </summary>
        protected static HookProc? keyboardHookproc;
        /// <summary>
        /// 条码信息（13为键盘钩子）
        /// </summary>
        protected BarcodeMessage barcodeMsg;
        /// <summary>
        /// 扫码枪是否启用状态-参数实例
        /// </summary>
        protected MSettingSystem? settingEnable;
        /// <summary>
        /// 扫码枪是否启用状态
        /// </summary>
        public bool IsEnable => this.settingEnable?.GetData(true) ?? true;

        /// <summary>
        /// 构造函数
        /// </summary>
        public BarcodeHookEx()
        {
            this.keyboardHookID = 0;
            this.barcodeMsg = new BarcodeMessage();
        }

        /// <summary>
        /// 启动安装钩子
        /// </summary>
        /// <returns></returns>
        public bool Start(MSettingSystem? barcodeSettingEnable)
        {
            try
            {
                settingEnable = barcodeSettingEnable;
                if (keyboardHookID != 0) return true;
                keyboardHookproc = new HookProc(KeyBoardHookProc);
                //GetModuleHandle 函数 替代 Marshal.GetHINSTANCE  
                //防止在 framework4.0中 注册钩子不成功  
                string strModuleName = Process.GetCurrentProcess().MainModule?.ModuleName ?? string.Empty;
                IntPtr modulePtr = ScanerHookEx.GetModuleHandle(strModuleName);
                //WH_KEYBOARD_LL=13  
                //全局钩子 WH_KEYBOARD_LL  
                //  hKeyboardHook = SetWindowsHookEx(13, hookproc, Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]), 0);  
                keyboardHookID = ScanerHookEx.SetWindowsHookEx(13, keyboardHookproc, modulePtr, 0);
                LoggerMgrcore.Instance.WriteInfo("BarcodeHookEx Start Succeed");
                return keyboardHookID != 0;
            }
            catch (Exception ep)
            {
                LoggerMgrcore.Instance.WriteError("BarcodeHookEx Start Exception", ep);
                return false;
            }
        }

        /// <summary>
        /// 停止卸载钩子
        /// </summary>
        /// <returns></returns>
        public bool Stop()
        {
            if (keyboardHookID == 0) return true;
            try
            {
                bool result = ScanerHookEx.UnhookWindowsHookEx(keyboardHookID);
                LoggerMgrcore.Instance.WriteInfo($"BarcodeHookEx Start {(result ? "Succeed" : "Failure")}");
                return result;
            }
            catch (Exception ep)
            {
                LoggerMgrcore.Instance.WriteError("BarcodeHookEx Stop Exception", ep);
                return false;
            }
            finally
            {
                keyboardHookID = 0;
            }
        }

        /// <summary>
        /// 键盘钩子程序
        /// </summary>
        /// <param name="nCode"></param>
        /// <param name="wParam"></param>
        /// <param name="lParam"></param>
        /// <returns></returns>
        protected int KeyBoardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            if (nCode != 0 || !IsEnable) 
                return ScanerHookEx.CallNextHookEx(this.keyboardHookID, nCode, wParam, lParam);

            var objScanerMsg = Marshal.PtrToStructure(lParam, typeof(ScanerMessage));
            if (objScanerMsg == null || wParam != 0x0100) 
                return ScanerHookEx.CallNextHookEx(this.keyboardHookID, nCode, wParam, lParam);

            ScanerMessage scanerMsg = (ScanerMessage)objScanerMsg;
            //解析条码信息
            this.barcodeMsg.Parse(scanerMsg);
            //解析完成，触发事件
            if (this.barcodeMsg.IsValid)
            {
                if (this.BarcodeHookEvent != null) this.BarcodeHookEvent(barcodeMsg);
                this.barcodeMsg.Reset();
            }
            return ScanerHookEx.CallNextHookEx(this.keyboardHookID, nCode, wParam, lParam);
        }
    }
}
